use rand::Rng;
use serde_json::Value;
use std::collections::HashMap;

#[derive(Debug, Clone)]
pub struct EconomicAgent {
    pub id: u32,
    pub agent_type: AgentType,
    pub resources: f64,
    pub behavior: BehaviorRules,
    pub history: Vec<AgentAction>,
}

#[derive(Debug, Clone)]
pub enum AgentType {
    Consumer,
    Producer,
    Government,
    Bank,
}

#[derive(Debug, Clone)]
pub struct BehaviorRules {
    pub risk_aversion: f64,
    pub spending_ratio: f64,
    pub saving_ratio: f64,
    pub behavioral_factors: economics::behavioral::BehavioralFactors,
}

#[derive(Debug, Clone)]
pub struct AgentAction {
    pub action_type: ActionType,
    pub amount: f64,
    pub timestamp: i64,
}

#[derive(Debug, Clone)]
pub enum ActionType {
    Produce,
    Consume,
    Invest,
    Tax,
    Regulate,
}

pub struct MarketSimulator {
    pub agents: Vec<EconomicAgent>,
    pub market_conditions: MarketConditions,
}

#[derive(Debug, Clone)]
pub struct MarketConditions {
    pub inflation: f64,
    pub interest_rate: f64,
    pub unemployment: f64,
}

impl MarketSimulator {
    pub fn new() -> Self {
        MarketSimulator {
            agents: Vec::new(),
            market_conditions: MarketConditions {
                inflation: 0.02,
                interest_rate: 0.03,
                unemployment: 0.05,
            },
        }
    }

    pub fn add_agent(&mut self, agent: EconomicAgent) {
        self.agents.push(agent);
    }

    pub fn simulate_step(&mut self) -> Value {
        let mut rng = rand::thread_rng();
        let mut market_data = HashMap::new();
        
        // Simulate each agent's behavior
        for agent in &mut self.agents {
            let action = match agent.agent_type {
                AgentType::Consumer => self.simulate_consumer(agent, &mut rng),
                AgentType::Producer => self.simulate_producer(agent, &mut rng),
                _ => AgentAction {
                    action_type: ActionType::Consume,
                    amount: 0.0,
                    timestamp: chrono::Local::now().timestamp(),
                },
            };
            
            agent.history.push(action);
        }

        // Update market conditions
        self.update_market_conditions();

        // Prepare simulation data
        market_data.insert("inflation", self.market_conditions.inflation.to_string());
        market_data.insert("interest_rate", self.market_conditions.interest_rate.to_string());
        market_data.insert("unemployment", self.market_conditions.unemployment.to_string());

        serde_json::to_value(market_data).unwrap()
    }

    fn simulate_consumer(&self, agent: &mut EconomicAgent, rng: &mut impl Rng) -> AgentAction {
        let mut spending = 0.0;
        
        if agent.behavior.should_consume() {
            spending = agent.behavior.consumption_amount().min(agent.resources);
            agent.resources -= spending;
        }
        
        AgentAction {
            action_type: ActionType::Consume,
            amount: spending,
            timestamp: chrono::Local::now().timestamp(),
        }
    }

    fn simulate_producer(&self, agent: &mut EconomicAgent, rng: &mut impl Rng) -> AgentAction {
        let production = agent.resources * 0.8; // Simple production rule
        let profit = production * (1.0 + rng.gen_range(-0.1..0.15));
        agent.resources += profit;
        
        AgentAction {
            action_type: ActionType::Produce,
            amount: production,
            timestamp: chrono::Local::now().timestamp(),
        }
    }

    fn update_market_conditions(&mut self) {
        // Simple market dynamics
        let total_actions: f64 = self.agents.iter()
            .map(|a| a.history.iter().map(|h| h.amount.abs()).sum::<f64>())
            .sum();
            
        let activity_ratio = total_actions / (self.agents.len() as f64 * 100.0).max(1.0);
        
        self.market_conditions.inflation = (self.market_conditions.inflation + 0.005 * activity_ratio).max(0.0);
        self.market_conditions.interest_rate = (self.market_conditions.interest_rate + 0.002 * activity_ratio).max(0.0);
        self.market_conditions.unemployment = (0.1 - 0.05 * activity_ratio).max(0.01);
    }
}